GraphQL の Persisted Queries について
https://gyazo.com/949d7ba09ef24c7afdeda25cd0122377
林家花園
GraphQL クエリの特徴
GraphQLではクライアントとサーバ間のやりとりにGraphQLクエリを使うことで、一回のリクエストで必要な要素だけを取得することができます。
code:sample_query
query GetCustomerQuery {
customer(id: "Customer001") {
id
email
profile {
id
name
}
}
}
通常はこのようなクエリをPOSTリクエストのペイロードに含めて、{ "query": "query GetCustomerQuery {...}" }のような形でサーバサイドにリクエストします。サーバサイドではこのクエリを解釈し、必要なオブジェクトや要素だけをクライアントに返却します。このようにして、クライアントはクエリを記述することによって一度に複数のネストしたオブジェクトを最低限必要な要素だけ取得することが可能になります。なお、上記の"Customer001"のような値は引数(variables)として渡すことが一般的ですがPersisted Queriesではvariablesを取り扱わないため省略します。
Persisted Queries とは
Persisted Queiesは、リクエストのペイロードにGraphQLクエリの文字列を直接含めるのではなく、ハッシュ化した文字列(ハッシュ値)を使ってリクエストする方法です。クライアントはハッシュ値をペイロードに入れてリクエストした上で、サーバサイドではハッシュ値をクエリに戻し、必要なデータを返します。
Persisted QueriesはGraphQLの機能を拡張したプロトコルです。そのため、Persisted Queriesに対応したクライアントでは以下のようなペイロードを送ります。
code:extensions.json
{
"extensions":{
"persistedQuery":{
"version":1,
"sha256Hash":"ハッシュ値"
}
}
}
クライアントはクエリをハッシュ化する必要があります。上記の例ではSHA256のハッシュアルゴリズムを使ってハッシュ値を生成しています。また、サーバサイドでは受け取ったハッシュ値をクエリに戻す必要があります。ここで、クエリとハッシュ値を変換する方法を2種類紹介します。
クエリとハッシュ値を相互に変換するテーブルを用意する
クエリとハッシュ値が相互に変換できればそれで良いので、クライアントとサーバ側でそれぞれ変換テーブルを事前に用意しておくことで対応させることが可能になります。変換テーブルはビルドステップで事前に準備したり、スクリプトを走らせて生成したりします。以下はJS環境で使うためにgraphql-codegen-persisted-query-idsという自動生成ツールを用いて作った json ファイルの例です。 code:client.json
{
"getCustomerQuery": "ハッシュ値"
}
code:server.json
{
"ハッシュ値": "query GetCustomerQuery {...}"
}
client.jsonをクライアントで、server.jsonをサーバサイドでそれぞれ使用します。クライアントではハッシュ値をそのまま取り扱うことはしたくないですが、このツールを使えばgetCustomerQueryというクエリの名前を使ってハッシュ値を取り出すことができます。便利ですね。
Automatic Persisted Queries で自動変換を行う
前述したような変換テーブルを用意することなく自動的に変換を行ってくれるようにする方法としてAutomatic Persisted Queriesがあります。Automatic Persisted Queriesを使う場合は、Apollo のようなそれに対応したサーバとクライアントを使います。仕組みとしては、クエリと対応するハッシュ値をクライアントで動的に生成し、クエリの代わりにハッシュ値をサーバサイドに送ります。もしサーバサイドでハッシュ値に対応するクエリがわからない場合はエラーを返します。そこで、クライアントは再度同じクエリをリクエストするのですが、その時にクエリ文字列とハッシュ値を両方ともペイロードに含めます。サーバサイドではハッシュ値とクエリを登録した上で結果を返します。それ以降登録されたクエリはハッシュ値だけ送ればよくなります。これを自動的に行ってくれる仕組みがAutomatic Persisted Queriesです。
Persisted Queries はどのような問題を解決するのか
データ通信量の削減
GraphQLで複雑なクエリを使用するとクエリ文字列が長くなるため、ペイロードサイズが大きくなりネットワークのパフォーマンスが低下します。Persisted Queriesを使用すると長いクエリであっても文字列長が同じハッシュ値を送るため、ペイロードサイズが削減できます。さらに、サイズが小さくなることでGraphQLクエリをGETリクエストで送信できます。GETリクエストにできれば一般的なCDNで結果をキャッシュできるようになるため、パフォーマンスがさらに向上します。
セキュアな通信の実現
GraphQLのクエリはスキーマさえ正しければどんなクエリでも受け付けることができます。複雑なクエリの中には処理の重いロジックや、深いネスト、無駄なプロパティが含まれる場合があります。また、場合によってはクライアントから悪意のあるクエリや想定外のクエリ(ただしスキーマ上は正しいクエリ)を含めたリクエストがくる場合もあるかもしれません。通常のクエリであれば、このようなクエリでもあってもスキーマ上正しければ値を返すしかありません(※クエリの複雑度を計算して閾値を超える場合にはエラーを返す方法は存在しますが、閾値を超えなければ正しいレスポンスを返すでしょう)。しかしPersisted Queriesを使うことによって事前に決められたクエリのハッシュ値のみを受け付けることができるようになるため、想定していない複雑なクエリや悪意のあるクエリをクライアントから送られても破棄することができます。
まとめ
Persisted Queriesそのものは非常にシンプルなんですが、GraphQLの拡張機能であるがゆえに体系だった解説記事が少ないなと思い今回まとめてみました。次回は、実際にやってみた例を紹介しようと思います。
https://i.gyazo.com/51454271bc5520c96d424a29a19498c4.png https://twitter.com/share?url=https%3A%2F%2Fscrapbox.io%2Fwada-blog%2FGraphQL_%25E3%2581%25AE_Persisted_Queries_%25E3%2581%25AB%25E3%2581%25A4%25E3%2581%2584%25E3%2581%25A6&text=GraphQL+%E3%81%AE+Persisted+Queries+%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6 < Twitterでシェア
参考
宣伝
株式会社モニクルでは、はたらく世代・子育て世代が抱えるお金や資産運用に関する不安や悩みを解決するお手伝いをさせていただき、現在から老後に至るまでの資金計画や最適なポートフォリオの提案を行っております。